package com.elite.groovy.callback

import com.alibaba.fastjson.parser.Feature
import com.alibaba.fastjson.serializer.SerializerFeature
import com.elite.groovy.kh.KHDBConfig
import com.elite.groovy.kh.KHUtil
import com.elite.groovy.kh.LogToDB
import com.elite.groovy.util.EliteBean
import com.elite.groovy.util.IpAddressUtil
import net.sf.json.JSONObject
import org.apache.commons.codec.binary.Base64
import org.apache.commons.codec.binary.Hex
import org.apache.commons.lang.StringUtils
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory

import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException

/**
 * @description: SignatureUtil 报价页面嵌入加密
 */
public class apiOpenSign implements ServiceBackInvoke {
    private static final Log log = LogFactory.getLog(apiOpenSign.class);

    String doCallBack(EliteBean eliteBean, HttpServletRequest request, HttpServletResponse response) {

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/text;charset=UTF-8");
        long startTime = System.currentTimeMillis();
        String outData = "";

        // 调用IP过滤
        if (KHDBConfig.getParam(eliteBean, "#APIIP") == "1" && !KHUtil.getRemoteHost(request)) {
            outData = "API被非法IP调用-Request Not Allow!" + IpAddressUtil.getIpAddress(request);
            log.warn(outData);
            return outData;
        }

        String getMethod = request.getMethod();
        log.debug("HTTP请求调用类型 getMethod:" + getMethod);
        if (getMethod != "POST" && getMethod != "GET") {
            outData = "HTTP请求调用类型错误，接口调用失败：" + getMethod;
            log.error(outData);
            return outData;
        }

        // 获取所有Header
        Map<String, String> mapHeader = new HashMap<String, String>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            log.debug("Call Header-" + key + ":" + value);

            mapHeader.put(key, value);
        }

        // 获取所有参数名
        Map<String, String> mapParam = new HashMap<String, String>();
        Enumeration ep = request.getParameterNames();
        while (ep.hasMoreElements()) {
            String key = (String) ep.nextElement();
            String value = request.getParameter(key);
            log.debug("Call Parameter-" + key + ":" + value);
            mapParam.put(key, value);

        }

        // 获取调用数据
        String Syncpram = "";
        if (getMethod.equals("GET")) {
            Syncpram = request.getQueryString();
            log.info("接收调用GET参数信息：" + Syncpram);
        } else if (getMethod.equals("POST")) {
            InputStreamReader reader = new InputStreamReader(request.getInputStream(), "UTF-8");
            BufferedReader iny = new BufferedReader(reader);
            String line;
            while ((line = iny.readLine()) != null) {
                Syncpram += line;
            }
            log.info("接收调用POST报文信息：" + System.getProperty("line.separator") + Syncpram);
        }

        // PrintWriter
        PrintWriter out = response.getWriter();

        try {
            // 解析请求报文
            JSONObject callJson = JSONObject.fromObject(Syncpram);

            String appId = KHUtil.GetSFJV(callJson, "appId");
            String appSecret = KHUtil.GetSFJV(callJson, "appSecret");
            String userCode = KHUtil.GetSFJV(callJson, "userCode");
            String reqTimestamp = KHUtil.GetSFJV(callJson, "reqTimestamp");

            // 处理待加密Map
            Map<String, String> dataMap = new HashMap(6);
            dataMap.put("appId", appId);
            dataMap.put("appSecret", appSecret);
            dataMap.put("userCode", userCode);
            dataMap.put("reqTimestamp", reqTimestamp);

            // 加密结果
            String data_Enc = encryptStr(dataMap);

            outData = data_Enc;
            log.debug("加密结果:" + data_Enc);

        } catch (Exception e) {
            outData = "HTTP请求调用错误，接口处理异常：" + e.getMessage();
            log.error(outData, e);

        } finally {
            LogToDB.toDB(eliteBean, "dataSource", "SignatureUtil 报价页面嵌入加密", "SignatureUtil", Syncpram, outData, "本次发送总耗时：" + (System.currentTimeMillis() - startTime).toString(), getMethod + ":" + mapParam.toString());

        }

        out.print(outData);
        out.flush();
        out.close();
    }

    public static String encryptStr(Map<String, String> params) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        String result = getEncryptString(params);
        MessageDigest mDigest = MessageDigest.getInstance("SHA1");
        byte[] res = mDigest.digest(result.getBytes());
        String hexStr = String.valueOf(Hex.encodeHex(res));
        return encode(hexStr.getBytes("UTF-8"));
    }

    private static String getEncryptString(Map<String, String> params) {
        if (StringUtils.isNotEmpty((String) params.get("body"))) {
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject((String) params.get("body"), new Feature[]{Feature.OrderedField});
            if (jsonObject.containsKey("file")) {
                jsonObject.remove("file");
                params.put("body", com.alibaba.fastjson.JSONObject.toJSONString(jsonObject, new SerializerFeature[]{SerializerFeature.WriteMapNullValue}));
            }
        }

        Collection<String> keyset = params.keySet();
        List<String> list = new ArrayList(keyset);
        Collections.sort(list);
        String result = "";

        for (int i = 0; i < list.size(); ++i) {
            result = result + (String) list.get(i) + "=" + (params.get(list.get(i)) == null ? "" : (String) params.get(list.get(i))) + "&";
        }

        if (StringUtils.isNotEmpty(result) && result.endsWith("&")) {
            result = result.substring(0, result.length() - 1);
        }

        return result;
    }

    public static String encode(byte[] data) {
        return (new Base64()).encodeAsString(data);
    }
}